<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    
    <title>PyMOTW: smtplib &mdash; PyMOTW Document v1.6 documentation</title>
    <link rel="stylesheet" href="../_static/mytest.css" type="text/css" />
    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
    <script type="text/javascript">
      var DOCUMENTATION_OPTIONS = {
        URL_ROOT:    '../',
        VERSION:     '1.6',
        COLLAPSE_MODINDEX: false,
        FILE_SUFFIX: '.html',
        HAS_SOURCE:  true
      };
    </script>
    <script type="text/javascript" src="../_static/jquery.js"></script>
    <script type="text/javascript" src="../_static/doctools.js"></script>
    
    <!-- comment utility -->
    <link rel="stylesheet" href="../_static/comment.css" type="text/css" />
    <script type="text/javascript" src="../_static/md5.js"></script>
    <script type="text/javascript" src="../_static/comment.js"></script>
    <!-- end -->
    <link rel="author" title="About these documents" href="../about.html" />
    <link rel="copyright" title="Copyright" href="../copyright.html" />
    <link rel="top" title="PyMOTW Document v1.6 documentation" href="../index.html" />
    <link rel="next" title="PyMOTW: Trace" href="trace.html" />
    <link rel="prev" title="PyMOTW: anydbm" href="anydbm.html" /> 
  </head>
  <body>
    <div class="related">
      <h3>Navigation</h3>
      <ul>
        <li class="right" style="margin-right: 10px">
          <a href="../genindex.html" title="General Index"
             accesskey="I">index</a></li>
        <li class="right" >
          <a href="trace.html" title="PyMOTW: Trace"
             accesskey="N">next</a> |</li>
        <li class="right" >
          <a href="anydbm.html" title="PyMOTW: anydbm"
             accesskey="P">previous</a> |</li>
        <li><a href="../index.html">PyMOTW Document v1.6 documentation</a> &raquo;</li> 
      </ul>
    </div> 
      <div class="sphinxsidebar">
        <div class="sphinxsidebarwrapper">
            <h3><a href="../index.html">Table Of Contents</a></h3>
            <ul>
<li><a class="reference external" href="">PyMOTW: smtplib</a><ul>
<li><a class="reference external" href="#id1">发送一封邮件</a></li>
<li><a class="reference external" href="#id2">认证和加密</a></li>
<li><a class="reference external" href="#id3">验证一个邮件地址</a></li>
<li><a class="reference external" href="#id4">参考</a></li>
</ul>
</li>
</ul>

            <h4>Previous topic</h4>
            <p class="topless"><a href="anydbm.html"
                                  title="previous chapter">PyMOTW: anydbm</a></p>
            <h4>Next topic</h4>
            <p class="topless"><a href="trace.html"
                                  title="next chapter">PyMOTW: Trace</a></p>
            <h3>This Page</h3>
            <ul class="this-page-menu">
              <li><a href="../_sources/documents/smtplib.txt"
                     rel="nofollow">Show Source</a></li>
            </ul>
          <div id="searchbox" style="display: none">
            <h3>Quick search</h3>
              <form class="search" action="../search.html" method="get">
                <input type="text" name="q" size="18" />
                <input type="submit" value="Go" />
                <input type="hidden" name="check_keywords" value="yes" />
                <input type="hidden" name="area" value="default" />
              </form>
              <p class="searchtip" style="font-size: 90%">
              Enter search terms or a module, class or function name.
              </p>
          </div>
          <script type="text/javascript">$('#searchbox').show(0);</script>
        </div>
      </div> 

    <div class="document">
      <div class="documentwrapper">
        <div class="bodywrapper">
          <div class="body">
            
  <div class="section" id="pymotw-smtplib">
<h1>PyMOTW: smtplib<a class="headerlink" href="#pymotw-smtplib" title="Permalink to this headline">¶</a></h1>
<ul class="simple">
<li>模块：smtplib</li>
<li>目的: 与smtp服务器交互, 提供邮件发送</li>
<li>python版本：1.5.2+</li>
</ul>
<p>smtplib包含了SMTP类, 用于与邮件服务器进行邮件通信.</p>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">在以下示例中, 邮件地址、主机名称、ip地址都是虚假的, 但是举例说明的命令副本和响应的信息都是存在的.</p>
</div>
<div class="section" id="id1">
<h2>发送一封邮件<a class="headerlink" href="#id1" title="Permalink to this headline">¶</a></h2>
<p>SMTP最常用的方法是连接服务器并发送一封邮件, 在构造器中指定邮件服务器名和端口名, 或者你可以使用connect()方法来指定. 一旦建立连接, 就可以调用sendmail()函数, 并附带信封体参数和消息内容, 消息文本应该与RFC2822兼容. smtplib不会自动修改消息内容和头信息, 这就意味着你需要自己添加From和To等头信息.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">smtplib</span>
<span class="kn">import</span> <span class="nn">email.utils</span>
<span class="kn">from</span> <span class="nn">email.mime.text</span> <span class="kn">import</span> <span class="n">MIMEText</span>

<span class="c"># Create the message</span>
<span class="n">msg</span> <span class="o">=</span> <span class="n">MIMEText</span><span class="p">(</span><span class="s">&#39;This is the body of the message.&#39;</span><span class="p">)</span>
<span class="n">msg</span><span class="p">[</span><span class="s">&#39;To&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">email</span><span class="o">.</span><span class="n">utils</span><span class="o">.</span><span class="n">formataddr</span><span class="p">((</span><span class="s">&#39;Recipient&#39;</span><span class="p">,</span> <span class="s">&#39;recipient@example.com&#39;</span><span class="p">))</span>
<span class="n">msg</span><span class="p">[</span><span class="s">&#39;From&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">email</span><span class="o">.</span><span class="n">utils</span><span class="o">.</span><span class="n">formataddr</span><span class="p">((</span><span class="s">&#39;Author&#39;</span><span class="p">,</span> <span class="s">&#39;author@example.com&#39;</span><span class="p">))</span>
<span class="n">msg</span><span class="p">[</span><span class="s">&#39;Subject&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s">&#39;Simple test message&#39;</span>

<span class="n">server</span> <span class="o">=</span> <span class="n">smtplib</span><span class="o">.</span><span class="n">SMTP</span><span class="p">(</span><span class="s">&#39;mail&#39;</span><span class="p">)</span>
<span class="n">server</span><span class="o">.</span><span class="n">set_debuglevel</span><span class="p">(</span><span class="bp">True</span><span class="p">)</span> <span class="c"># show communication with the server显示与服务器的通信情况</span>
<span class="k">try</span><span class="p">:</span>
    <span class="n">server</span><span class="o">.</span><span class="n">sendmail</span><span class="p">(</span><span class="s">&#39;author@example.com&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s">&#39;recipient@example.com&#39;</span><span class="p">],</span> <span class="n">msg</span><span class="o">.</span><span class="n">as_string</span><span class="p">())</span>
<span class="k">finally</span><span class="p">:</span>
    <span class="n">server</span><span class="o">.</span><span class="n">quit</span><span class="p">()</span>
</pre></div>
</div>
<p>在这个示例中, 调试开关被打开了, 这样可以显示客户端和服务端之间的通讯信息. 否则, 示例不会显示任何信息.</p>
<div class="highlight-python"><pre>$ python smtplib_sendmail.py
send: 'ehlo localhost.local\r\n'
reply: '250-mail.example.com Hello [192.168.1.17], pleased to meet you\r\n'
reply: '250-ENHANCEDSTATUSCODES\r\n'
reply: '250-PIPELINING\r\n'
reply: '250-8BITMIME\r\n'
reply: '250-SIZE\r\n'
reply: '250-DSN\r\n'
reply: '250-ETRN\r\n'
reply: '250-AUTH GSSAPI DIGEST-MD5 CRAM-MD5\r\n'
reply: '250-DELIVERBY\r\n'
reply: '250 HELP\r\n'
reply: retcode (250); Msg: mail.example.com Hello [192.168.1.17], pleased to meet you
ENHANCEDSTATUSCODES
PIPELINING
8BITMIME
SIZE
DSN
ETRN
AUTH GSSAPI DIGEST-MD5 CRAM-MD5
DELIVERBY
HELP
send: 'mail FROM:&lt;author@example.com&gt; size=266\r\n'
reply: '250 2.1.0 &lt;author@example.com&gt;... Sender ok\r\n'
reply: retcode (250); Msg: 2.1.0 &lt;author@example.com&gt;... Sender ok
send: 'rcpt TO:&lt;recipient@example.com&gt;\r\n'
reply: '250 2.1.5 &lt;recipient@example.com&gt;... Recipient ok\r\n'
reply: retcode (250); Msg: 2.1.5 &lt;recipient@example.com&gt;... Recipient ok
send: 'data\r\n'
reply: '354 Enter mail, end with "." on a line by itself\r\n'
reply: retcode (354); Msg: Enter mail, end with "." on a line by itself
data: (354, 'Enter mail, end with "." on a line by itself')
send: 'From nobody Sun Sep 28 10:02:48 2008\r\nContent-Type: text/plain; charset="us-ascii"\r\nMIME-Version: 1.0\r\nContent-Transfer-Encoding: 7bit\r\nTo: Recipient &lt;recipient@example.com&gt;\r\nFrom: Author &lt;author@example.com&gt;\r\nSubject: Simple test message\r\n\r\nThis is the body of the message.\r\n.\r\n'
reply: '250 2.0.0 m8SE2mpc015614 Message accepted for delivery\r\n'
reply: retcode (250); Msg: 2.0.0 m8SE2mpc015614 Message accepted for delivery
data: (250, '2.0.0 m8SE2mpc015614 Message accepted for delivery')
send: 'quit\r\n'
reply: '221 2.0.0 mail.example.com closing connection\r\n'
reply: retcode (221); Msg: 2.0.0 mail.example.com closing connection</pre>
</div>
<p>注意sendmail的第二个参数, 收件人信息需要是一个list结构, 你可以在list写上很多的邮件地址, message会依次把消息发送给他们. 由于信封信息和和邮件头是分开的, 所以你可以通过一些方法参数来指定密送一些人, 但不可以在邮件头中设置.</p>
</div>
<div class="section" id="id2">
<h2>认证和加密<a class="headerlink" href="#id2" title="Permalink to this headline">¶</a></h2>
<p>SMTP同样可以处理认证和TLS(一种底层通讯的安全协议)加密. 如果服务器支持它们, 你可以自己来检测服务器是否支持TLS, 可以直接调用ehlo()来鉴定并询问服务器支持何种类型扩展. 然后通过调用has_extn()来检查结果. 一旦启动TLS, 你可以在认证之前再次调用ehlo().</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">smtplib</span>
<span class="kn">import</span> <span class="nn">email.utils</span>
<span class="kn">from</span> <span class="nn">email.mime.text</span> <span class="kn">import</span> <span class="n">MIMEText</span>
<span class="kn">import</span> <span class="nn">getpass</span>

<span class="c"># Prompt the user for connection info</span>
<span class="n">to_email</span> <span class="o">=</span> <span class="nb">raw_input</span><span class="p">(</span><span class="s">&#39;Recipient: &#39;</span><span class="p">)</span>
<span class="n">servername</span> <span class="o">=</span> <span class="nb">raw_input</span><span class="p">(</span><span class="s">&#39;Mail server name: &#39;</span><span class="p">)</span>
<span class="n">username</span> <span class="o">=</span> <span class="nb">raw_input</span><span class="p">(</span><span class="s">&#39;Mail user name: &#39;</span><span class="p">)</span>
<span class="n">password</span> <span class="o">=</span> <span class="n">getpass</span><span class="o">.</span><span class="n">getpass</span><span class="p">(</span><span class="s">&quot;</span><span class="si">%s</span><span class="s">&#39;s password: &quot;</span> <span class="o">%</span> <span class="n">username</span><span class="p">)</span>

<span class="c"># Create the message</span>
<span class="n">msg</span> <span class="o">=</span> <span class="n">MIMEText</span><span class="p">(</span><span class="s">&#39;Test message from PyMOTW.&#39;</span><span class="p">)</span>
<span class="n">msg</span><span class="o">.</span><span class="n">set_unixfrom</span><span class="p">(</span><span class="s">&#39;author&#39;</span><span class="p">)</span>
<span class="n">msg</span><span class="p">[</span><span class="s">&#39;To&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">email</span><span class="o">.</span><span class="n">utils</span><span class="o">.</span><span class="n">formataddr</span><span class="p">((</span><span class="s">&#39;Recipient&#39;</span><span class="p">,</span> <span class="n">to_email</span><span class="p">))</span>
<span class="n">msg</span><span class="p">[</span><span class="s">&#39;From&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">email</span><span class="o">.</span><span class="n">utils</span><span class="o">.</span><span class="n">formataddr</span><span class="p">((</span><span class="s">&#39;Author&#39;</span><span class="p">,</span> <span class="s">&#39;author@example.com&#39;</span><span class="p">))</span>
<span class="n">msg</span><span class="p">[</span><span class="s">&#39;Subject&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s">&#39;Test from PyMOTW&#39;</span>

<span class="n">server</span> <span class="o">=</span> <span class="n">smtplib</span><span class="o">.</span><span class="n">SMTP</span><span class="p">(</span><span class="n">servername</span><span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
    <span class="n">server</span><span class="o">.</span><span class="n">set_debuglevel</span><span class="p">(</span><span class="bp">True</span><span class="p">)</span>

    <span class="c"># identify ourselves, prompting server for supported features</span>
    <span class="n">server</span><span class="o">.</span><span class="n">ehlo</span><span class="p">()</span>

    <span class="c"># If we can encrypt this session, do it</span>
    <span class="k">if</span> <span class="n">server</span><span class="o">.</span><span class="n">has_extn</span><span class="p">(</span><span class="s">&#39;STARTTLS&#39;</span><span class="p">):</span>
         <span class="n">server</span><span class="o">.</span><span class="n">starttls</span><span class="p">()</span>
         <span class="n">server</span><span class="o">.</span><span class="n">ehlo</span><span class="p">()</span> <span class="c"># re-identify ourselves over TLS connection</span>

    <span class="n">server</span><span class="o">.</span><span class="n">login</span><span class="p">(</span><span class="n">username</span><span class="p">,</span> <span class="n">password</span><span class="p">)</span>
    <span class="n">server</span><span class="o">.</span><span class="n">sendmail</span><span class="p">(</span><span class="s">&#39;author@example.com&#39;</span><span class="p">,</span> <span class="p">[</span><span class="n">to_email</span><span class="p">],</span> <span class="n">msg</span><span class="o">.</span><span class="n">as_string</span><span class="p">())</span>
<span class="k">finally</span><span class="p">:</span>
    <span class="n">server</span><span class="o">.</span><span class="n">quit</span><span class="p">()</span>
</pre></div>
</div>
<p>注意STARTTLS不会出现在扩展列表中, 因为启动了TLS.</p>
<div class="highlight-python"><pre>$ python smtplib_authenticated.py
Recipient: recipient@example.com
Mail server name: smtpauth.isp.net
Mail user name: user@isp.net
user@isp.net's password:
send: 'ehlo localhost.local\r\n'
reply: '250-elasmtp-isp.net Hello localhost.local [&lt;your IP here&gt;]\r\n'
reply: '250-SIZE 14680064\r\n'
reply: '250-PIPELINING\r\n'
reply: '250-AUTH PLAIN LOGIN CRAM-MD5\r\n'
reply: '250-STARTTLS\r\n'
reply: '250 HELP\r\n'
reply: retcode (250); Msg: elasmtp-isp.net Hello localhost.local [&lt;your IP here&gt;]
SIZE 14680064
PIPELINING
AUTH PLAIN LOGIN CRAM-MD5
STARTTLS
HELP
send: 'STARTTLS\r\n'
reply: '220 TLS go ahead\r\n'
reply: retcode (220); Msg: TLS go ahead
send: 'ehlo localhost.local\r\n'
reply: '250-elasmtp-isp.net Hello localhost.local [&lt;your IP here&gt;]\r\n'
reply: '250-SIZE 14680064\r\n'
reply: '250-PIPELINING\r\n'
reply: '250-AUTH PLAIN LOGIN CRAM-MD5\r\n'
reply: '250 HELP\r\n'
reply: retcode (250); Msg: elasmtp-isp.net Hello farnsworth.local [&lt;your IP here&gt;]
SIZE 14680064
PIPELINING
AUTH PLAIN LOGIN CRAM-MD5
HELP
send: 'AUTH CRAM-MD5\r\n'
reply: '334 PDExNjkyLjEyMjI2MTI1NzlAZWxhc210cC1tZWFseS5hdGwuc2EuZWFydGhsaW5rLm5ldD4=\r\n'
reply: retcode (334); Msg: PDExNjkyLjEyMjI2MTI1NzlAZWxhc210cC1tZWFseS5hdGwuc2EuZWFydGhsaW5rLm5ldD4=
send: 'ZGhlbGxtYW5uQGVhcnRobGluay5uZXQgN2Q1YjAyYTRmMGQ1YzZjM2NjOTNjZDc1MDQxN2ViYjg=\r\n'
reply: '235 Authentication succeeded\r\n'
reply: retcode (235); Msg: Authentication succeeded
send: 'mail FROM:&lt;author@example.com&gt; size=221\r\n'
reply: '250 OK\r\n'
reply: retcode (250); Msg: OK
send: 'rcpt TO:&lt;recipient@example.com&gt;\r\n'
reply: '250 Accepted\r\n'
reply: retcode (250); Msg: Accepted
send: 'data\r\n'
reply: '354 Enter message, ending with "." on a line by itself\r\n'
reply: retcode (354); Msg: Enter message, ending with "." on a line by itself
data: (354, 'Enter message, ending with "." on a line by itself')
send: 'Content-Type: text/plain; charset="us-ascii"\r\nMIME-Version: 1.0\r\nContent-Transfer-Encoding: 7bit\r\nTo: Recipient &lt;recipient@example.com&gt;\r\nFrom: Author &lt;author@example.com&gt;\r\nSubject: Test from PyMOTW\r\n\r\nTest message from PyMOTW.\r\n.\r\n'
reply: '250 OK id=1KjxNj-00032a-Ux\r\n'
reply: retcode (250); Msg: OK id=1KjxNj-00032a-Ux
data: (250, 'OK id=1KjxNj-00032a-Ux')
send: 'quit\r\n'
reply: '221 elasmtp-isp.net closing connection\r\n'
reply: retcode (221); Msg: elasmtp-isp.net closing connection</pre>
</div>
</div>
<div class="section" id="id3">
<h2>验证一个邮件地址<a class="headerlink" href="#id3" title="Permalink to this headline">¶</a></h2>
<p>SMTP协议包含一个命令可以询问服务器一个邮件地址是否合法, 通常VRFY是关闭的, 以防止垃圾邮件发送者找到合法的邮件地址, 但是, 如果它打开, 你可以向服务器询问这个邮件地址并接受一个状态码, 如果是可用的, 那么会返回一个可用的完整用户名.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">smtplib</span>

<span class="n">server</span> <span class="o">=</span> <span class="n">smtplib</span><span class="o">.</span><span class="n">SMTP</span><span class="p">(</span><span class="s">&#39;mail&#39;</span><span class="p">)</span>
<span class="n">server</span><span class="o">.</span><span class="n">set_debuglevel</span><span class="p">(</span><span class="bp">True</span><span class="p">)</span> <span class="c"># show communication with the server</span>
<span class="k">try</span><span class="p">:</span>
    <span class="n">dhellmann_result</span> <span class="o">=</span> <span class="n">server</span><span class="o">.</span><span class="n">verify</span><span class="p">(</span><span class="s">&#39;dhellmann&#39;</span><span class="p">)</span>
    <span class="n">notthere_result</span> <span class="o">=</span> <span class="n">server</span><span class="o">.</span><span class="n">verify</span><span class="p">(</span><span class="s">&#39;notthere&#39;</span><span class="p">)</span>
<span class="k">finally</span><span class="p">:</span>
    <span class="n">server</span><span class="o">.</span><span class="n">quit</span><span class="p">()</span>

<span class="k">print</span> <span class="s">&#39;dhellmann:&#39;</span><span class="p">,</span> <span class="n">dhellmann_result</span>
<span class="k">print</span> <span class="s">&#39;notthere :&#39;</span><span class="p">,</span> <span class="n">notthere_result</span>
</pre></div>
</div>
<p>最后二行输出中表示, 地址dhellmann是合法的, notthere是非法的.</p>
<div class="highlight-python"><pre>$ python smtplib_verify.py
send: 'vrfy &lt;dhellmann&gt;\r\n'
reply: '250 2.1.5 Doug Hellmann &lt;dhellmann@mail.example.com&gt;\r\n'
reply: retcode (250); Msg: 2.1.5 Doug Hellmann &lt;dhellmann@mail.example.com&gt;
send: 'vrfy &lt;notthere&gt;\r\n'
reply: '550 5.1.1 &lt;notthere&gt;... User unknown\r\n'
reply: retcode (550); Msg: 5.1.1 &lt;notthere&gt;... User unknown
send: 'quit\r\n'
reply: '221 2.0.0 mail.example.com closing connection\r\n'
reply: retcode (221); Msg: 2.0.0 mail.example.com closing connection
dhellmann: (250, '2.1.5 Doug Hellmann &lt;dhellmann@mail.example.com&gt;')
notthere : (550, '5.1.1 &lt;notthere&gt;... User unknown')</pre>
</div>
</div>
<div class="section" id="id4">
<h2>参考<a class="headerlink" href="#id4" title="Permalink to this headline">¶</a></h2>
<ul class="simple">
<li><a class="reference external" href="http://www.faqs.org/rfcs/rfc821.html">RFC 821: Simple Mail Transfer Protocol</a></li>
<li><a class="reference external" href="http://www.faqs.org/rfcs/rfc822.html">RFC 822: Standard for the Format of ARPA Internet Text Messages</a></li>
<li><a class="reference external" href="http://www.faqs.org/rfcs/rfc1869.html">RFC 1869: SMTP Service Extensions</a></li>
<li><a class="reference external" href="http://www.faqs.org/rfcs/rfc2822.html">RFC 2822: Internet Message Format</a></li>
<li><a class="reference external" href="http://docs.python.org/lib/module-smtplib.html">标准库文档: smtplib</a></li>
</ul>
</div>
</div>


          </div>
        </div>
      </div>
      <div class="clearer"></div>
    </div>
    <div class="related">
      <h3>Navigation</h3>
      <ul>
        <li class="right" style="margin-right: 10px">
          <a href="../genindex.html" title="General Index"
             >index</a></li>
        <li class="right" >
          <a href="trace.html" title="PyMOTW: Trace"
             >next</a> |</li>
        <li class="right" >
          <a href="anydbm.html" title="PyMOTW: anydbm"
             >previous</a> |</li>
        <li><a href="../index.html">PyMOTW Document v1.6 documentation</a> &raquo;</li> 
      </ul>
    </div>
    <div class="footer">
      &copy; <a href="../copyright.html">Copyright</a> 2009, vbarter &amp; liz.
      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.3.
    </div>
  </body>
</html>